/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TIMELINE_MANAGER_H
#define TIMELINE_MANAGER_H

#include <set>
#include <map>
#include <vector>
#include <thread>
#include <linux/netlink.h>
#include "sensor_if.h"

#include "timeline_data_utils.h"
#include "itimeline_algorithm.h"
#include "itimeline_callback.h"
#include "timeline_database_info.h"
#include "timeline_common.h"


#define random(a,b) (rand()%(b-a)+a)
#define ALL_POSITION_NUM 30
#define ITERATIONS 3
#define STAYTIME 1

namespace OHOS {
namespace Msdp {
class TimelineService;
class TimelineManager {
public:
    explicit TimelineManager(const wptr<TimelineService>& ms) : ms_(ms)
    {
        TIMELINE_HILOGI(TIMELINE_MODULE_SERVICE, "TimelineManager instance is created.");
    }
    ~TimelineManager() = default;

    class TimelineCallbackDeathRecipient : public IRemoteObject::DeathRecipient {
    public:
        TimelineCallbackDeathRecipient() = default;
        virtual void OnRemoteDied(const wptr<IRemoteObject> &remote);
        virtual ~TimelineCallbackDeathRecipient() = default;
    };


    struct Oclock {
        int totalnumber;
        int homenumber;
        int companynumber;
        int unknownnumber;
    };

    struct Rate {
        double homerate;
        double companyrate;
        double unknownrate;
    };

    enum EventType {
		EVENT_UEVENT_FD,
		EVENT_TIMER_FD,
    };

    struct SsidInfo {
        std::string SSID;
        int number = 1;
    };

    struct BssidInfo {
        std::string BSSID;
        int number = 1;
    };

    struct Position {
        double xpos = -1000;
        double ypos;
        
        int startYear;
        int startMonth;
        int startDay;
        int startHour;
        int startMin;
        int startSec;
        int endYear;
        int endMonth;
        int endDay;
        int endHour;
        int endMin;
        int endSec;
        std::string ssid;
        std::string bssid;
    };

    Oclock oclock[24];
    Rate rate[24];
    TimelineDatabaseInfo::ForcecastPosition forcecastPosition;
    std::vector<TimelineDatabaseInfo::ListData> listData;
    SsidInfo ssidInfo;
    std::vector<SsidInfo> SsidInfoTemp;
    BssidInfo bssidInfo;
    std::vector<BssidInfo> BssidInfoTemp;

    bool Init();
    bool GetData(TimelineDatabaseInfo::MovementData &data);
    void NotifyTimelineChange(const TimelineDataUtils::TimelineData& timelineData);
    void Subscribe(const TimelineDataUtils::TimelineArea& area, const sptr<ITimelineCallback>& callback);
    void UnSubscribe(const TimelineDataUtils::TimelineArea& area, const sptr<ITimelineCallback>& callback);
    bool UpdatePositionState(int32_t homevalue, int32_t companyvalue);
    // tm getTime(int timestring);
    int32_t LbsPositionDataCallback(const struct SensorEvents *event, const TimelineDataUtils::TimelineArea& area);
    void ReadRecentOneMonthData();
    bool UpdateHomePosition(double longitude, double latitude);
    bool UpdateCompanyPosition(double longitude, double latitude);
    
    bool UpdateRestTime(int32_t resttimestart, int32_t resttimeend);
    bool UpdateWorkTime(int32_t worktimestart, int32_t worktimeend);

    bool GetHomePosition();
    bool GetCompanyPosition();
    uint32_t GetRestTimeStart();
    uint32_t GetRestTimeEnd();
    uint32_t GetWorkTimeStart();
    uint32_t GetWorkTimeEnd();
    void GetTraceRate();
    void CheckRate(uint32_t time);
    TimelineDatabaseInfo::ForcecastPosition GetForcecastPosition();
    void InitKmeansTimer();
    void KmeansTimerCallback();
    void InitCheckRateTimer();
    void CheckRateTimerCallback();
    int RegisterTimerCallback(const int fd, const EventType et);
    void SetTimerInterval(int interval);
    void StartThread();
    void LoopingThreadEntry();
    bool ForcecastNextPosition();
    bool AddRate();
    double Rad(double positionInfo);
    double GetDistance(Position pos1, Position pos2);
    std::string GetSsidInfo(const std::vector<TimelineDatabaseInfo::ListData> &Temp);
    std::string GetPositionSsidInfo(const std::vector<SsidInfo> &ssidInfo);
    std::string GetBssidInfo(const std::vector<TimelineDatabaseInfo::ListData> &Temp);
    std::string GetPositionBssidInfo(const std::vector<BssidInfo> &bssidInfo);
    void CheckPosition(std::vector<TimelineDatabaseInfo::ListData>  &cluser, int positionHugeDiffNumber_, int positionHugeDiffTotalNumber_);

private:
    using Callback = std::function<void(TimelineManager*)>;
    std::map<int32_t, Callback> callbacks_;
    
    struct TimelineInfo {
        double longitude;
        double latitude;
        int duration;
        struct tm time;
    };

    struct classcomp {
        bool operator()(const sptr<ITimelineCallback> &l, const sptr<ITimelineCallback> &r) const {
            return l->AsObject() < r->AsObject();
        }
    };

    std::string SSID_;
    std::string BSSID_;
    // int GetDistance(Position pos1, Position pos2);
    int GetCluster(Position means[], Position point);
    Position GetMeans(std::vector<Position> cluster);
    void Kmeans(const std::vector<TimelineDatabaseInfo::ListData> &listData);
    

    const wptr<TimelineService> ms_;
    std::mutex mutex_;
    sptr<IRemoteObject::DeathRecipient> timelineCBDeathRecipient_;
    std::map<TimelineDataUtils::TimelineArea, std::set<const sptr<ITimelineCallback>, classcomp>> listenerMap_;
    std::vector<Position> centerMean_;
    std ::shared_ptr<TimelineDatabaseInfo> timelinedatabaseinfo_;
    int timerInterval_ = -1;
    int32_t managerEpFd_ = -1;
    int32_t kmeansTimerFd_ = -1;
	int32_t rateTimerFd_ = -1;
    int32_t homevalue_  {0};
    int32_t companyvalue_ {1};
    double homelongitude_;
    double homelatitude_;
    double companylongitude_;
    double companylatitude_;

    int32_t resttimestart_ {22};
    int32_t resttimeend_ {6};
    int32_t worktimestart_ {9};
    int32_t worktimeend_ {18};

    double companyMeanLongitude_;
    double companyMeanLatitude_;
    double homeMeanLongitude_;
    double homeMeanLatitude_;
    int getOnceMonthDataFlag_ {0};
    int homeHumanSetFlag_ {0};
    int companyHumanSetFlag_ {0};
    int kmeansUpdateFlag_ {0};
    int positionOneHugeDiffNumber_ {0};
    int positionOneHugeDiffTotalNumber_ {0};
    int positionTwoHugeDiffNumber_ {0};
    int positionTwoHugeDiffTotalNumber_ {0};
    int clearVectorFlag_ {0};
    int homeMeansHugDiffNumber_ {0};
    int companyMeansHugDiffNumber_ {0};
    std::string homeBssid_;
    std::string companySsid_;
    TimelineDatabaseInfo::ForcecastPosition forcecastPosition_;
    TimelineDatabaseInfo::ForcecastPosition forcecastPositionTemp_ = TimelineDatabaseInfo::ForcecastPosition::UNKNOWN;
    // TimelineDataUtils::TimelineData latestTimelineDataCache;
    // const struct SensorInterface *sensorInterface_ = nullptr;
};
} // namespace Msdp
} // namespace OHOS
#endif // TIMELINE_MANAGER_H
